/*                          UX-Framework                               
 *                                                                 
 *  iZE Co.,Ltd. Copyright 2009 All rights reserved.          
 *  This file is distributed under the terms of the GNU Lesser 
 *  General Public License, described in file LICENSE.                                     
 */
package jp.ize.ux.acts;

// {{{ imports
import jp.ize.ux.UXObject;
import jp.ize.ux.acts.Act;
import jp.ize.ux.geom.UXPoint;
import jp.ize.ux.utils.Util;
import jp.ize.ux.tween.UXTween;
// }}}
// {{{ typedef MoveActParameter
typedef MoveActParameter =
{
	> ActParameter,
	// {{{ var point : UXPoint;
	/**
	 * 移動終了地点です。
	 */
	var point : UXPoint;
	// }}}
}
// }}}
// {{{ typedef CurvingMoveActParameter
typedef CurvingMoveActParameter =
{
	> ActParameter,
	// {{{ var p0 : UXPoint;
	/**
	 * 移動開始地点です。
	 */
	var p0 : UXPoint;
	// }}}
	// {{{ var p1 : UXPoint;
	/**
	 * コントロールポイントです。
	 */
	var p1 : UXPoint;
	// }}}
	// {{{ var p2 : UXPoint;
	/**
	 * 移動終了地点です。
	 */
	var p2 : UXPoint;
	// }}}
}
// }}}
// {{{ typedef RotateActParameter
typedef RotateActParameter =
{
	> ActParameter,
	// {{{ var center : UXPoint;
	/**
	 * 回転の中心点です。
	 */
	var center : UXPoint;
	// }}}
	// {{{ var radius : Float;
	/**
	 * 回転の半径です。
	 */
	var radius : Float;
	// }}}
	// {{{ var starta : Float;
	/**
	 * 回転の開始角度です。
	 */
	var starta : Float;
	// }}}
	// {{{ var enda : Float;
	/**
	 * 回転の終了角度です。
	 */
	var enda : Float;
	// }}}
}
// }}}
// {{{ typedef CurvingState
typedef CurvingState =
{
	var state : BasicStateType;
	var p0    : UXPoint;
	var p1    : UXPoint;
	var p2    : UXPoint;
}
// }}}
// {{{ class MoveAct extends Act
/**
 * MoveActクラス<br>
 * 直線上の動きを表現するクラスです。<br>
 *
 * @author		iZE Co., Ltd.<br>
 * @version		$Id$<br>
 */
class MoveAct extends Act
{
	// {{{ public function new()
	/**
	 * コンストラクタ。
	 */
	public function new()
	{
		super();
	}
	// }}}
	// {{{ public function move( ?map:MoveActParameter, ?interp:BasicStateType->MoveActParameter ) : BasicStateType -> Void
	/**
	 * 直線上に子コンポーネントを並べるアクションです。
	 */
	public function move( ?map:MoveActParameter, ?interp:BasicStateType->MoveActParameter ) : BasicStateType -> Void
	{
		var me = this;
		return function( state : BasicStateType ) : Void {
			var param = map;
			if ( interp!=null ) param = interp(state);
			var getter = function(obj:UXObject): TPoint {
				return {x:obj.x,y:obj.y};
			};
			var setter = function(obj:UXObject,init:TPoint,end:TPoint,v:Float):Void {
				obj.x = init.x + (end.x-init.x) * v;
				obj.y = init.y + (end.y-init.y) * v;
			};
			var end = {
				x:param.point.x,
				y:param.point.y
			};
			var tw = new UXTween<UXObject,TPoint>(state.target, end, getter, setter,
						param.time, param.transition);
			tw.setEndTweenHandler( function(e:Dynamic){
				if ( state.subject!=null ) {
					state.subject.notify(Act.STOP);
				}
			});
			var id = "move";
			if ( !me.tm.objects.exists(id) ) {
				me.tm.registObject(id,state);
			}
			me.tm.addTweenChain(id,tw); 
			me.tm.start(id,false,state.target);
		};
	}
	// }}}
	// {{{ public function curvingMove( ?cmp:CurvingMoveActParameter, ?interp:BasicStateType->CurvingMoveActParameter ) : BasicStateType -> Void
	/**
	 * 直線上に子コンポーネントを並べるアクションです。
	 */
	public function curvingMove( ?cmp:CurvingMoveActParameter, ?interp:BasicStateType->CurvingMoveActParameter ) : BasicStateType -> Void
	{
		var me = this;
		return function( state : BasicStateType ) : Void {
			var param = cmp;
			if ( interp!=null ) param = interp(state);
			if ( param.p0==null ) param.p0 = new UXPoint(state.target.x,state.target.y);
			var curving_state:CurvingState = {
				state: state,
				p0: param.p0,
				p1: param.p1,
				p2: param.p2
			};
			var getter = function(obj:CurvingState): TPoint {
				return {x:obj.state.target.x,y:obj.state.target.y};
			};
			var end = {
				x:param.p2.x,
				y:param.p2.y
			};
			var tw = new UXTween<CurvingState,TPoint>(curving_state, end, getter, me.curvingMoveSetter,
						param.time, param.transition);
			tw.setEndTweenHandler( function(e:Dynamic){
				if ( state.subject!=null ) {
					state.subject.notify(Act.STOP);
				}
			});
			var id = "move";
			if ( !me.tm.objects.exists(id) ) {
				me.tm.registObject(id,state);
			}
			me.tm.addTweenChain(id,tw); 
			me.tm.start(id,false,state.target);
		};
	}
	// }}}
	// {{{ public function rotate( ?rap:RotateActParameter, ?interp:BasicStateType->RotateActParameter ) : BasicStateType -> Void
	/**
	 * 直線上に子コンポーネントを並べるアクションです。
	 */
	public function rotate( ?rap:RotateActParameter, ?interp:BasicStateType->RotateActParameter ) : BasicStateType -> Void
	{
		var me = this;
		return function( state : BasicStateType ) : Void {
			var param = rap;
			if ( interp!=null ) param = interp(state);
			var getter = function(obj:UXObject): {v:Float} {
				return {v:param.starta*Math.PI/180};
			};
			var setter = function(obj:UXObject, init:{v:Float}, end:{v:Float}, v:Float) {
				var val = init.v+(end.v-init.v)*v;
				obj.x = param.center.x + param.radius * Math.cos(val);
				obj.y = param.center.y - param.radius * Math.sin(val);
			};
			var end = {v:param.enda * Math.PI / 180};
			var tw = new UXTween<UXObject,{v:Float}>(state.target, end, getter, setter, param.time, param.transition);
			tw.setEndTweenHandler( function(e:Dynamic){
				if ( state.subject!=null ) {
					state.subject.notify(Act.STOP);
				}
			});
			var id = "move";
			if ( !me.tm.objects.exists(id) ) {
				me.tm.registObject(id,state);
			}
			me.tm.addTweenChain(id,tw); 
			me.tm.start(id,false,state.target);
		};
	}
	// }}}
	// {{{ public function curvingMoveSetter(obj:CurvingState,init:TPoint,end:TPoint,v:Float) : Void
	/**
	* ベジエ曲線の座標を計算します。
	*/
	inline public function curvingMoveSetter(obj:CurvingState,init:TPoint,end:TPoint,v:Float) : Void
	{
		var p = getBezierPoint(obj.p0, obj.p1, obj.p2, v);
		obj.state.target.x = p.x;
		obj.state.target.y = p.y;
	}

	// }}}
	// {{{ public function getBezierPoint(p0:TPoint, p1:TPoint, p2:TPoint, t:Float):TPoint

	inline public function getBezierPoint(p0:TPoint, p1:TPoint, p2:TPoint, t:Float):TPoint
	{
		return {
				x:(1-t)*(1-t)*p0.x + 2*t*(1-t)*p1.x + t*t*p2.x,
				y:(1-t)*(1-t)*p0.y + 2*t*(1-t)*p1.y + t*t*p2.y
		};
	}

	// }}}
}
// }}}
